package com.formulas.component.extension.register;

import com.formulas.component.extension.BizScenario;
import com.formulas.component.extension.ExtensionCoordinate;

import java.util.function.Consumer;
import java.util.function.Function;

/**
 * 抽象组件执行器
 * @author yiwannuofulasi
 * @date 2023/6/12 17:21
 */
public abstract class AbstractComponentExecutor {

    /**
     * 使用响应执行扩展:这段代码是一个通用的执行方法，可以执行指定类型的组件的指定函数，并将结果转换为指定类型。
     * 其中，参数targetClz指定了组件的类型，bizScenario指定了业务场景，exeFunction是一个函数，用于执行组件的某个方法并返回结果。
     * 在该方法内部，首先通过locateComponent方法获取指定类型的组件实例，然后使用exeFunction执行组件方法并返回结果。
     * 该方法可以方便地执行各种类型的组件，提高了代码的通用性和可维护性。
     *
     * @param targetClz 指定了组件的类型
     * @param bizScenario 指定了业务场景
     * @param exeFunction 用于执行组件的某个方法并返回结果
     * @param <R> Response Type
     * @param <T> Parameter Type
     */
    public <R, T> R execute(Class<T> targetClz, BizScenario bizScenario, Function<T, R> exeFunction) {
        T component = locateComponent(targetClz, bizScenario);
        return exeFunction.apply(component);
    }

    /**
     * 使用响应执行扩展
     * @param extensionCoordinate 扩展协调
     * @param exeFunction 用于执行组件的某个方法并返回结果
     * @param <R>  Response Type
     * @param <T> Parameter Type
     */
    public <R, T> R execute(ExtensionCoordinate extensionCoordinate, Function<T, R> exeFunction){
        return execute((Class<T>) extensionCoordinate.getExtensionPointClass(), extensionCoordinate.getBizScenario(), exeFunction);
    }

    /**
     * 执行扩展而不响应:执行一个无返回值的函数
     *
     * @param targetClz 指定了组件的类型
     * @param context 指定了业务场景
     * @param exeFunction 执行函数
     * @param <T> Parameter Type
     */
    public <T> void executeVoid(Class<T> targetClz, BizScenario context, Consumer<T> exeFunction) {
        T component = locateComponent(targetClz, context);
        exeFunction.accept(component);
    }

    /**
     * 执行扩展而不响应
     * @param extensionCoordinate 扩展协调
     * @param exeFunction 执行函数
     * @param <T> Parameter Type
     */
    public <T> void executeVoid(ExtensionCoordinate extensionCoordinate, Consumer<T> exeFunction){
        executeVoid(extensionCoordinate.getExtensionPointClass(), extensionCoordinate.getBizScenario(), exeFunction);
    }

    /**
     * 定位并返回一个指定类型的组件
     * @param targetClz 指定了组件的类型
     * @param context 指定了业务场景
     * @return 符合指定组件指定场景的bean
     */
    protected abstract <C> C locateComponent(Class<C> targetClz, BizScenario context);
}
